/**
 *
 */
package org.tangdao.common.plugins;

import java.sql.Connection;
import java.util.Map;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.StatementType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.tangdao.common.lang.StringUtils;
import org.tangdao.common.reflect.ReflectUtils;
import org.tangdao.common.suports.BaseEntity;
import org.tangdao.common.suports.DataScopeSqlMap;
import org.tangdao.common.suports.Page;
import org.tangdao.common.web.http.ServletUtils;

import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler;

import lombok.Setter;
import lombok.experimental.Accessors;

/**
 * 数据范围拦截
 * 
 * @author Ryan Ru(ruyangit@gmail.com)
 */

@Setter
@Accessors(chain = true)
@Intercepts({
		@Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class }) })
public class DataScopeInterceptor extends AbstractSqlParserHandler implements Interceptor {

	protected static final Log logger = LogFactory.getLog(DataScopeInterceptor.class);

	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
		MetaObject metaObject = SystemMetaObject.forObject(statementHandler);

		// SQL 解析
		this.sqlParser(metaObject);

		MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
		// 用于日志处理
		HttpServletRequest request = ServletUtils.getRequest();
		if (request != null) {
			request.setAttribute(SqlCommandType.class.getName(), mappedStatement.getSqlCommandType());
		}
		// 先判断是不是SELECT操作 (2019-04-10 00:37:31 跳过存储过程)
		if (SqlCommandType.SELECT != mappedStatement.getSqlCommandType()
				|| StatementType.CALLABLE == mappedStatement.getStatementType()) {
			return invocation.proceed();
		}
		// 针对定义了rowBounds，做为mapper接口方法的参数
		BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
		Object parameterObj = boundSql.getParameterObject();
		// 判断是否进行数据过滤
		DataScopeSqlMap dataScopeSqlMap = findDataScopeSqlMapObject(parameterObj);
		String dsfSql;
		if(dataScopeSqlMap!=null&&StringUtils.isNotBlank(dsfSql = (String)dataScopeSqlMap.get("dsf"))) {
			metaObject.setValue("delegate.boundSql.sql", boundSql.getSql() + dsfSql);
		}
		return invocation.proceed();
	}

	@Override
	public Object plugin(Object target) {
		// 生成代理对象
		return Plugin.wrap(target, this);
	}

	@Override
	public void setProperties(Properties properties) {

	}
	
	/**
     * 查找参数是否包括DataScope对象
     */
    public DataScopeSqlMap findDataScopeSqlMapObject(Object parameterObj) {
    	DataScopeSqlMap dataScopeSqlMap = null;
        if (parameterObj instanceof DataScopeSqlMap) {
        	dataScopeSqlMap =  (DataScopeSqlMap) parameterObj;
        } else if (parameterObj instanceof Map) {
            for (Object obj : ((Map<?, ?>) parameterObj).values()) {
            	if(obj instanceof Page) {
            		continue;
            	}
            	if(obj instanceof BaseEntity) {
            		dataScopeSqlMap = ReflectUtils.getFieldValue(obj, "dataScopeSqlMap");
            	}
            	if(dataScopeSqlMap!=null&&dataScopeSqlMap.size()>0) {
            		return dataScopeSqlMap;
            	}
            }
        }
        return dataScopeSqlMap;
    }

}
